﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace csharp_async_callback
{
    public delegate string Delegate(out int iExecThread);

    class Program
    {
        static string AsyncMethod(out int iExecThread)
        {
            iExecThread = AppDomain.GetCurrentThreadId();
            for(int i=0;i<10;i++)
            {
                Console.WriteLine("AsyncMethod: " + i);
            }
            return "AsyncMethod return!!!";
        }

        static void AsyncCallback(IAsyncResult ar)
        {
            int iExecThread;

            Delegate dg = (Delegate)ar.AsyncState;
            string asyncReturn = dg.EndInvoke(out iExecThread, ar);

            Console.WriteLine("Async Callback: " + asyncReturn);
        }

        static void noCallback()
        {
            Delegate dg = new Delegate(AsyncMethod);
            int iExecThread;

            IAsyncResult ar = dg.BeginInvoke(out iExecThread, null, null);

            for (int i = 0; i < 100; i++)
            {
                Console.WriteLine("main: " + i);
            }

            // AsyncMethod가 끝마칠때까지 Main의 프로세스를 대기
            ar.AsyncWaitHandle.WaitOne();

            /*
             * 호출 폴링 호출 패턴을 이용도 가능 
             */
            /*while (!ar.IsCompleted)
            {
                Thread.Sleep(10);
            }*/

            string asyncReturn = dg.EndInvoke(out iExecThread, ar);
            Console.WriteLine("Async Callback: " + asyncReturn);
        }

        static void withCallback()
        {
            Delegate dg = new Delegate(AsyncMethod);
            int iExecThread;

            AsyncCallback cb = new AsyncCallback(AsyncCallback);
            IAsyncResult ar = dg.BeginInvoke(out iExecThread, cb, dg);

            for (int i = 0; i < 100; i++)
            {
                Console.WriteLine("main: " + i);
            }
        }
        
        static void Main(string[] args)
        {
            Console.WriteLine("start noCallback!!!!");
            noCallback();

            Console.WriteLine("start Callback!!!!");
            withCallback();

            Console.WriteLine("Press Anykey");
            Console.ReadKey();
        }
    }
}
